
/**
 * @name MASS L3 Heatwave Detects unusually hot days from simulation sample data
 * for January 2-31, 1980 Part of Pacific Northwest Climate Data Analysis
 * Project Proof of concept for MASS parallelization techniques to read netCDF
 * data
 *
 * @version 0.1.302 Alpha, MASS L3 Heatwave, 2nd commit
 * @date 9/05/2013
 * @author Niko Simonson
 * @author Brett Yasutake
 *
 */
// IMPORTS
import MASS.*;                  // MASS Library
import java.io.IOException;     // IO Exceptions
import java.util.*;             // Vectors, etc.
import ucar.ma2.ArrayFloat;     // for netCDF reader
import ucar.ma2.IndexIterator;  // for netCDF reader
import ucar.nc2.NetcdfFile;     // for netCDF reader
import ucar.nc2.Variable;       // for netCDF reader

public class MassL3Heatwave extends Place {

    // CONSTANTS - MASS arguments
    private static final String[] MASSARGS = {"dslab", "dslab-302",
        "machinefile.txt", "12345"};    // connection arguments
    private static final int NPROCESSES = 1;    // number of processes to employ
    private static final int NTHREADS = 2;      // number of threads to employ
    private static final int HANDLE = 0;        // unique Places handle number
    // CONSTANTS - functions
    private static final int init_ = 0;          // initialize Places\
    
    private static final int computeTemp_ = 1;   // compute regional avg temps
    private static final int reportTemps_ = 2;       // exchange regional temps
//    private static final int computeMax_ = 3;    // compute daily max temps
//    private static final int computeAvg_ = 4;
//    private static final int reportMax_ = 5;
//    // pacNW functions
//    private static final int initR_ = 10;
//    private static final int computeMaxR_ = 11;
//    private static final int reportMaxR_ = 12;
//    private static final int computeAvgR_ = 13;
//    private static final int reportAvgR_ = 14;
//    private static final int computeVarR_ = 15;
//    private static final int reportVarR_ = 16;
//    private static final int computeThresholdR_ = 17;
//    private static final int reportThresholdR_ = 18;
//    private static final int computeHeatWaveR_ = 19;
//    // CONSTANTS - heatwave constants
    private static final int DAYS = 30;          // days of data collection
    private static final int DAYSEGMENTS = 4;    // time slices per day
    // target variable T2: temperature at 2 meters above surface
    private static final String TARGET = "T2";
    // northwest regional climate data sample
    private static final String FILENAMEBEGIN = "/home/brett/netcdf_files/1980_jan/wrfout_d02_1980-01-";
    private static final String FILENAMEEND = ":00:00";  // end of file name
    private static final int XRANGE = 123;
    private static final int YRANGE = 162;
    // VARIABLES
    private int sizeX, myX; // time slices in a day
    private int sizeY, myY; // days
    private double avgTemp; // regional average temperature ********************
    private String fileName; // target file
    private double[][] region;

    // PARALLELIZATION FUNCTIONS
    /**
     * *************CONSTRUCTOR
     *
     ***********************************
     * @name MassL1Heatwave
     * @param interval unused Empty constructor required for MASS Place
     * implementation
     * ***********************************************************
     */
    public MassL3Heatwave(Object interval) {
        // A constructor implementation is required for MASS Place

    }

    /**
     * @name callMethod Provides enumerated list of functions to be parallelized
     * in MASS
     *
     * @param funcId - function ID (listed as Constants)
     * @param args - function parameters
     * @return - unused
     */
    public Object callMethod(int funcId, Object args) {
        switch (funcId) {
            case init_:
                return init(args);
            case computeTemp_:
                return computeTemp(args);
            case reportTemps_:
                return reportTemps(args);
            case 3:
                return getPlace(args);

        }
        return null;
    }

    /**
     * @name init Initialization information for MASS Places index[0]: days
     * index[1]: time slices in a day
     *
     * @param args MASS initialization arguments, # of processes, # of threads
     * @return unused
     */
    public Object init(Object args) {

        region = new double[XRANGE][YRANGE];
        return null;
    }
    
        /**
     * @name computeTemp Open netCDF file and compute average temperature over
     * the entire region
     *
     * @param args unused
     * @return true = success, false = exception occurred
     */
    public Object computeTemp(Object args) {
        // VARIABLES
        NetcdfFile stubby = null; // target netCDF file

        avgTemp = 0.0;
        try {
            // open target netCDF file
            fileName = getFileName(myX, myY);
            stubby = NetcdfFile.open(fileName, null);	// Open the file

            // Find target variable
            Variable target = stubby.findVariable(TARGET);
            // Get list of file's variables
            List<Variable> stubbyVars = stubby.getVariables();
            Variable curr = stubbyVars.get(stubbyVars.indexOf(target));

            // Read values from variable (temperatures over the region)
            ArrayFloat.D3 d3values = (ArrayFloat.D3) curr.read();
            double totalTemp = 0.0;

            int x = 0;
            int y = 0;

            IndexIterator iter = d3values.getIndexIterator();
            while (iter.hasNext()) {
                iter.next();
//                totalTemp += (double) iter.getFloatCurrent();
                region[x][y] = (double) iter.getFloatCurrent();

                if (y == YRANGE - 1) {
                    x++;
                    y = 0;
                } else {
                    y++;
                }
            }
            // calculate regional average temperature
            avgTemp = totalTemp / d3values.getSize();
            return (Object) true;
        } catch (java.io.IOException e) {
            e.printStackTrace();
            return (Object) false;
        } catch (Exception e) {
            e.printStackTrace();
            return (Object) false;
        } finally {		// Close out the file no matter what occurs
            if (stubby != null) {
                try {
                    stubby.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
    
            return (Object) null;
        }
    }

    /**
     * @name getFileName Private helper function to dynamically generate correct
     * file name
     *
     * @param thisX daily time slice
     * @param thisY day
     *
     * @return
     */
    private String getFileName(int thisX, int thisY) {
        // VARIABLES
        String strX, strY;  // file component numbers

        // calculate correct day of the month
        strY = Integer.toString(thisY + 2);

        // calculate correct time of the day
        strX = Integer.toString(thisX * 6);

        // adjust for numbers less than 10
        if (Integer.parseInt(strX) < 10) {
            strX = "0" + strX;
        }
        if (Integer.parseInt(strY) < 10) {
            strY = "0" + strY;
        }

        // return proper file name
        return FILENAMEBEGIN + strY + "_" + strX + FILENAMEEND;
    }
    
    
        
    public double[][] reportTemps(Object args) {
        return region;
    }
    
    public Object getPlace(Object args) {
        return this.getPlace(null);
    }
}